package org.dxy.infrastructure.persistent.repository;

import cn.hutool.core.util.EnumUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.adapter.repository.IRouteRepository;
import org.dxy.domain.event.route.*;
import org.dxy.domain.model.aggregate.Route;
import org.dxy.domain.model.aggregate.impl.RouteAggRoot;
import org.dxy.domain.model.valobj.RouteId;
import org.dxy.infrastructure.entity.DomainEventEntity;
import org.dxy.infrastructure.persistent.service.DomainEventService;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @description: 工艺路线仓储实现类
 * @author: dxy
 * @createTime: 2025/6/29 12:05
 */
@Slf4j
@Repository
@RequiredArgsConstructor
public class RouteRepository implements IRouteRepository {
    private final DomainEventService domainEventService;
    private final ObjectMapper objectMapper;

    @Override
    public void save(Route route) {
        // 保存逻辑通常由事件存储服务处理
        // 这里可以添加额外的保存逻辑，如快照存储等
    }

    @Override
    public Route findById(Long routeId) {
        List<DomainEventEntity> domainEventEntityList = domainEventService.getEventListByAggregateId(routeId);

        if (domainEventEntityList == null || domainEventEntityList.isEmpty()) {
            log.error("工艺路线 {} 没有相关事件", routeId);
            return null;
        }

        return replayEvents(routeId, domainEventEntityList);
    }

    @Override
    public boolean existsByCode(String routeCode) {
        // TODO: 实现根据编码检查工艺路线是否存在的逻辑
        // 这里可以通过查询事件存储或读模型来实现
        return false;
    }

    /**
     * 通过事件重放重建工艺路线聚合根
     * @param routeId 工艺路线ID
     * @param eventEntities 事件实体列表
     * @return 重建的工艺路线聚合根
     */
    private Route replayEvents(Long routeId, List<DomainEventEntity> eventEntities) {
        RouteAggRoot.RouteAggRootBuilder builder = RouteAggRoot.builder()
                .routeId(RouteId.of(routeId));
        
        try {
            RouteAggRoot route = builder.build();
            
            for (DomainEventEntity eventEntity : eventEntities) {
                applyEvent(route, eventEntity);
            }
            
            // 清理重放过程中可能产生的事件
            route.clearDomainEvents();

            log.debug("成功回放工艺路线 {} 的 {} 条事件", routeId, eventEntities.size());
            return route;
            
        } catch (Exception e) {
            log.error("Failed to replay events for routeId: {}", routeId, e);
            throw new RuntimeException("事件重放失败: " + e.getMessage(), e);
        }
    }

    /**
     * 应用单个事件到聚合根
     * @param route 工艺路线聚合根
     * @param eventEntity 事件实体
     */
    private void applyEvent(RouteAggRoot route, DomainEventEntity eventEntity) {
        try {
            String eventType = eventEntity.getEventType();
            String eventData = eventEntity.getEventData();

            if (eventType == null) {
                log.error("工艺路线ID {} 的事件类型为空，无法处理事件。", eventEntity.getAggregateId());
                return;
            }

            RouteEventTypeEnum eventTypeEnum = EnumUtil.getBy(
                    RouteEventTypeEnum.class,
                    p -> eventType.equals(p.getKey())
            );

            if (eventTypeEnum == null) {
                log.error("工艺路线ID {} 的事件类型未知：{}，无法处理事件。", eventEntity.getAggregateId(), eventType);
                return;
            }

            switch (eventTypeEnum) {
                case CREATED -> {
                    RouteCreatedEvent event = objectMapper.readValue(eventData, RouteCreatedEvent.class);
                    route.applyCreatedEvent(event);
                }
                case UPDATED -> {
                    RouteUpdatedEvent event = objectMapper.readValue(eventData, RouteUpdatedEvent.class);
                    route.applyUpdatedEvent(event);
                }
                case ENABLED -> {
                    RouteEnabledEvent event = objectMapper.readValue(eventData, RouteEnabledEvent.class);
                    route.applyEnabledEvent(event);
                }
                case DISABLED -> {
                    RouteDisabledEvent event = objectMapper.readValue(eventData, RouteDisabledEvent.class);
                    route.applyDisabledEvent(event);
                }
                case PUBLISHED -> {
                    RoutePublishedEvent event = objectMapper.readValue(eventData, RoutePublishedEvent.class);
                    route.applyPublishedEvent(event);
                }
                case ARCHIVED -> {
                    RouteArchivedEvent event = objectMapper.readValue(eventData, RouteArchivedEvent.class);
                    route.applyArchivedEvent(event);
                }
                case PROCESSES_ASSIGNED -> {
                    RouteProcessesAssignedEvent event = objectMapper.readValue(eventData, RouteProcessesAssignedEvent.class);
                    route.applyProcessesAssignedEvent(event);
                }
                case STEP_ADDED -> {
                    RouteStepAddedEvent event = objectMapper.readValue(eventData, RouteStepAddedEvent.class);
                    route.applyStepAddedEvent(event);
                }
                case STEP_REMOVED -> {
                    RouteStepRemovedEvent event = objectMapper.readValue(eventData, RouteStepRemovedEvent.class);
                    route.applyStepRemovedEvent(event);
                }
                case STEP_REORDERED -> {
                    RouteStepReorderedEvent event = objectMapper.readValue(eventData, RouteStepReorderedEvent.class);
                    route.applyStepReorderedEvent(event);
                }
                case STEP_UPDATED -> {
                    RouteStepUpdatedEvent event = objectMapper.readValue(eventData, RouteStepUpdatedEvent.class);
                    route.applyStepUpdatedEvent(event);
                }
                default -> {
                    log.warn("工艺路线ID {} 的事件类型 {} 未处理。", eventEntity.getAggregateId(), eventTypeEnum);
                }
            }
            
        } catch (Exception e) {
            log.error("应用工艺路线ID {} 的事件类型 {} 失败，异常信息：", eventEntity.getAggregateId(), eventEntity.getEventType(), e);
            throw new RuntimeException("应用事件失败: " + e.getMessage(), e);
        }
    }
}
